home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / CUGUK / COMMS / C101.ZIP / UUPC11XT.ZIP / RN / INTRP.C < prev    next >
C/C++ Source or Header  |  1992-11-21  |  36KB  |  1,332 lines

  1. /* $Header: E:\SRC\UUPC\RN\RCS/INTRP.C 1.1 1992/11/21 06:14:58 ahd Exp $
  2.  *
  3.  * $Log: INTRP.C $
  4.  * Revision 1.1  1992/11/21  06:14:58  ahd
  5.  * Initial
  6.  *
  7.  *
  8.  *    Rev 1.0   18 Nov 1990  0:21:54
  9.  * Initial revision.
  10.  * Revision 4.3.2.4  90/04/23  00:31:20  sob
  11.  * Removed unneeded atoi call.
  12.  *
  13.  * Revision 4.3.2.3  90/03/22  23:04:35  sob
  14.  * Fixes provided by Wayne Davison <drivax!davison>
  15.  *
  16.  * Revision 4.3.2.2  90/03/17  17:03:12  sob
  17.  * Fixed determination of the news superuser's id. Fix provided by Chip
  18.  * Rosenthal <chip@chinacat.lonestar.org>.
  19.  *
  20.  * Revision 4.3.2.1  89/12/17  02:54:55  sob
  21.  * Removed redundant include directive.
  22.  *
  23.  * Revision 4.3.1.5  85/05/23  17:21:24  lwall
  24.  * Now allows 'r' and 'f' on null articles.
  25.  *
  26.  * Revision 4.3.1.4  85/05/21  13:35:21  lwall
  27.  * Sped up "rn -c" by not doing unnecessary initialization.
  28.  *
  29.  * Revision 4.3.1.3  85/05/17  10:37:11  lwall
  30.  * Fixed & substitution to capitalize last name too.
  31.  *
  32.  * Revision 4.3.1.2  85/05/15  14:39:45  lwall
  33.  * Spelled gecos right.
  34.  *
  35.  * Revision 4.3.1.1  85/05/10  11:33:51  lwall
  36.  * Branch for patches.
  37.  *
  38.  * Revision 4.3  85/05/01  11:40:54  lwall
  39.  * Baseline for release with 4.3bsd.
  40.  *
  41.  */
  42.  
  43. #include <stdio.h>
  44. #include <time.h>
  45.  
  46. #include "lib.h"
  47. #include "importng.h"
  48.  
  49. /*--------------------------------------------------------------------*/
  50. /*                    UUPC/extended include files                     */
  51. /*--------------------------------------------------------------------*/
  52.  
  53. #include "pushpop.h"
  54.  
  55. #ifdef msdos
  56. #include <process.h>
  57. #endif
  58.  
  59. #include "EXTERN.h"
  60. #include "common.h"
  61. #include "util.h"
  62. #include "search.h"
  63. #include "head.h"
  64. #include "rn.h"
  65. #include "artsrch.h"
  66. #include "ng.h"
  67. #include "respond.h"
  68. #include "rcstuff.h"
  69. #include "bits.h"
  70. #include "artio.h"
  71. #include "term.h"
  72. #include "final.h"
  73. #include "INTERN.h"
  74. #include "intrp.h"
  75.  
  76. char *orgname = ORGNAME;
  77.  
  78. /* name of this site */
  79.  
  80. #ifdef GETHOSTNAME
  81. char *hostname;
  82.  
  83. #undef SITENAME
  84. #define SITENAME hostname
  85. #else                        /* !GETHOSTNAME */
  86.  
  87. #ifdef DOUNAME
  88. #include <sys/utsname.h>
  89. struct utsname uts;
  90.  
  91. #undef SITENAME
  92. #define SITENAME uts.nodename
  93. #else                        /* !DOUNAME */
  94.  
  95. #ifdef PHOSTNAME
  96. char *hostname;
  97.  
  98. #undef SITENAME
  99. #define SITENAME hostname
  100. #else                        /* !PHOSTNAME */
  101.  
  102. #ifdef WHOAMI
  103. #undef SITENAME
  104. #define SITENAME sysname
  105. #endif                       /* WHOAMI */
  106.  
  107. #endif                       /* PHOSTNAME */
  108.  
  109. #endif                       /* DOUNAME */
  110.  
  111. #endif                       /* GETHOSTNAME */
  112.  
  113. #ifdef TILDENAME
  114. static char *tildename = Nullch;
  115. static char *tildedir = Nullch;
  116.  
  117. #endif
  118.  
  119. char *realname INIT(Nullch); /* real name of sender
  120.                               * from /etc/passwd */
  121.  
  122. char *dointerp();
  123. char *getrealname();
  124.  
  125. #ifdef CONDSUB
  126. char *skipinterp();
  127.  
  128. #endif
  129.  
  130. static void abort_interp();
  131.  
  132. void
  133.   intrp_init(tcbuf)
  134.    char *tcbuf;
  135. {
  136.    char *getlogin();
  137.  
  138.    /* get environmental stuff */
  139.  
  140. #ifdef msdos
  141.    if (E_organization)
  142.       orgname = E_organization;
  143. #endif                       /* msdos */
  144.  
  145.    /* get home directory */
  146.  
  147.  
  148. #ifdef msdos
  149.    if (homedir == Nullch)
  150.       homedir = E_homedir;
  151. #endif                       /* msdos */
  152.  
  153.    if (homedir == Nullch)
  154.       homedir = getenv("HOME");
  155.  
  156.    if (homedir == Nullch)
  157.       homedir = getenv("LOGDIR");
  158.  
  159.    dotdir = getval("DOTDIR", homedir);
  160.  
  161.    /* get login name */
  162.  
  163.    if (logname == Nullch)
  164.       logname = getenv("USER");
  165.    if (logname == Nullch)
  166.       logname = getenv("LOGNAME");
  167.  
  168. #ifdef GETLOGIN
  169.    if (logname == Nullch)
  170.       logname = savestr(getlogin());
  171. #endif
  172.  
  173. #ifdef msdos
  174.    if (logname == Nullch)
  175.       logname = E_mailbox;
  176. #endif
  177.  
  178.    if (checkflag)            /* that getwd below
  179.                               * takes ~1/3 sec. */
  180.       return;                /* and we do not need it
  181.                               * for -c */
  182.    getwd(tcbuf);             /* find working directory name */
  183.    PushDir(".");
  184.    atexit( PopDir );
  185.    origdir = savestr(tcbuf); /* and remember it */
  186.  
  187.    /* get the real name of the person (%N) */
  188.    /* Must be done after logname is read in because BERKNAMES uses that */
  189.  
  190. #ifdef msdos
  191.    strcpy(tcbuf, E_name);
  192. #else
  193.    strcpy(tcbuf, getrealname(getuid()));
  194. #endif
  195.  
  196.    realname = savestr(tcbuf);
  197.  
  198.    /* name of header file (%h) */
  199.  
  200.    headname = savestr(filexp(HEADNAME));
  201.  
  202.    /* name of this site (%H) */
  203.  
  204. #ifdef GETHOSTNAME
  205.    gethostname(buf, sizeof buf);
  206.    hostname = savestr(buf);
  207. #else
  208.  
  209. #ifdef DOUNAME
  210.    /* get sysname */
  211.    uname(&uts);
  212. #else
  213.  
  214. #ifdef PHOSTNAME
  215.    {
  216.       FILE *popen();
  217.       FILE *pipefp = popen(PHOSTNAME, "r");
  218.  
  219.       if (pipefp == Nullfp)
  220.       {
  221.          printf("Can't find hostname\n");
  222.          sig_catcher(0);
  223.       }
  224.       fgets(buf, sizeof buf, pipefp);
  225.       buf[strlen(buf) - 1] = '\0';      /* wipe out newline */
  226.       hostname = savestr(buf);
  227.       pclose(pipefp);
  228.    }
  229. #endif
  230.  
  231. #endif
  232.  
  233. #endif
  234.  
  235.    sitename = savestr(SITENAME);
  236. }
  237.  
  238. /* expand filename via %, ~, and $ interpretation */
  239. /* returns pointer to static area */
  240. /* Note that there is a 1-deep cache of ~name interpretation */
  241.  
  242. char *
  243.   filexp(s)
  244.    register char *s;
  245. {
  246.    static char filename[CBUFLEN];
  247.    char scrbuf[CBUFLEN];
  248.    register char *d;
  249.  
  250. #ifdef DEBUGGING
  251.    if (debug & DEB_FILEXP)
  252.       printf("< %s\n", s) FLUSH;
  253. #endif
  254.  
  255.    interp(filename, (sizeof filename), s);      /* interpret any %
  256.                                                  * escapes */
  257.  
  258. #ifdef DEBUGGING
  259.    if (debug & DEB_FILEXP)
  260.       printf("%% %s\n", filename) FLUSH;
  261. #endif
  262.  
  263.    s = filename;
  264.    if (*s == '~')
  265.    {                         /* does destination
  266.                               * start with ~? */
  267.       if (!*(++s) || *s == '/')
  268.       {
  269.          sprintf(scrbuf, "%s%s", homedir, s);
  270.          /* swap $HOME for it */
  271.  
  272. #ifdef DEBUGGING
  273.          if (debug & DEB_FILEXP)
  274.             printf("~ %s\n", scrbuf) FLUSH;
  275. #endif
  276.  
  277.          strcpy(filename, scrbuf);
  278.       }
  279.       else
  280.       {
  281.  
  282. #ifdef TILDENAME
  283.          for (d = scrbuf; isalnum(*s); s++, d++)
  284.             *d = *s;
  285.          *d = '\0';
  286.          if (tildedir && strEQ(tildename, scrbuf))
  287.          {
  288.             strcpy(scrbuf, tildedir);
  289.             strcat(scrbuf, s);
  290.             strcpy(filename, scrbuf);
  291.  
  292. #ifdef DEBUGGING
  293.             if (debug & DEB_FILEXP)
  294.                printf("r %s %s\n", tildename, tildedir) FLUSH;
  295. #endif
  296.          }
  297.          else
  298.          {
  299.             if (tildename)
  300.             {
  301.                free(tildename);
  302.                free(tildedir);
  303.             }
  304.             tildedir = Nullch;
  305.             tildename = savestr(scrbuf);
  306.  
  307. #ifdef GETPWENT              /* getpwnam() is not the
  308.                               * paragon of efficiency */
  309.             {
  310.                struct passwd *getpwnam();
  311.                struct passwd *pwd = getpwnam(tildename);
  312.  
  313.                sprintf(scrbuf, "%s%s", pwd->pw_dir, s);
  314.                tildedir = savestr(pwd->pw_dir);
  315.  
  316. #ifdef NEWSADMIN
  317.                if ((pwd != NULL) && strEQ(newsadmin, tildename))
  318.                   newsuid = pwd->pw_uid;
  319. #endif
  320.  
  321.                strcpy(filename, scrbuf);
  322.  
  323. #ifdef GETPWENT
  324.                endpwent();
  325. #endif
  326.             }
  327. #else                        /* this will run faster,
  328.                               * and is less D space */
  329.             {                /* just be sure
  330.                               * LOGDIRFIELD is
  331.                               * correct */
  332.                FILE *pfp = fopen("/etc/passwd", "r");
  333.                char tmpbuf[512];
  334.                int i;
  335.  
  336.                if (pfp == Nullfp)
  337.                {
  338.                   printf(cantopen, "passwd") FLUSH;
  339.                   sig_catcher(0);
  340.                }
  341.                while (fgets(tmpbuf, 512, pfp) != Nullch)
  342.                {
  343.                   d = cpytill(scrbuf, tmpbuf, ':');
  344.  
  345. #ifdef DEBUGGING
  346.                   if (debug & DEB_FILEXP)
  347.                      printf("p %s\n", tmpbuf) FLUSH;
  348. #endif
  349.  
  350.                   if (strEQ(scrbuf, tildename))
  351.                   {
  352.  
  353. #ifdef NEWSADMIN
  354.                      if (strEQ(newsadmin, tildename))
  355.                         newsuid = atoi(index(d + 1, ':') + 1);
  356. #endif
  357.  
  358.                      for (i = LOGDIRFIELD - 2; i; i--)
  359.                      {
  360.                         if (d)
  361.                            d = index(d + 1, ':');
  362.                      }
  363.                      if (d)
  364.                      {
  365.                         cpytill(scrbuf, d + 1, ':');
  366.                         tildedir = savestr(scrbuf);
  367.                         strcat(scrbuf, s);
  368.                         strcpy(filename, scrbuf);
  369.                      }
  370.                      break;
  371.                   }
  372.                }
  373.                fclose(pfp);
  374.             }
  375. #endif
  376.          }
  377. #else                        /* !TILDENAME */
  378.  
  379. #ifdef VERBOSE
  380.          IF(verbose)
  381.             fputs("~loginname not implemented.\n", stdout) FLUSH;
  382.          ELSE
  383. #endif
  384.  
  385. #ifdef TERSE
  386.             fputs("~login not impl.\n", stdout) FLUSH;
  387. #endif
  388.  
  389. #endif
  390.       }
  391.    }
  392.    else if (*s == '$')
  393.    {                         /* starts with some env
  394.                               * variable? */
  395.       d = scrbuf;
  396.       *d++ = '%';
  397.       if (s[1] == '{')
  398.          strcpy(d, s + 2);
  399.       else
  400.       {
  401.          *d++ = '{';
  402.          for (s++; isalnum(*s); s++)
  403.             *d++ = *s;
  404.          /* skip over token */
  405.          *d++ = '}';
  406.          strcpy(d, s);
  407.       }
  408.  
  409. #ifdef DEBUGGING
  410.       if (debug & DEB_FILEXP)
  411.          printf("$ %s\n", scrbuf) FLUSH;
  412. #endif
  413.  
  414.       interp(filename, (sizeof filename), scrbuf);
  415.       /* this might do some extra '%'s but */
  416.       /* that is how the Mercedes Benz */
  417.    }
  418.  
  419. #ifdef DEBUGGING
  420.    if (debug & DEB_FILEXP)
  421.       printf("> %s\n", filename) FLUSH;
  422. #endif
  423.  
  424.    return filename;
  425. }
  426.  
  427. #ifdef CONDSUB
  428. /* skip interpolations */
  429.  
  430. char *
  431.   skipinterp(pattern, stoppers)
  432.    register char *pattern;
  433.    char *stoppers;
  434. {
  435.  
  436.    while (*pattern && (!stoppers || !index(stoppers, *pattern)))
  437.    {
  438.  
  439. #ifdef DEBUGGING
  440.       if (debug & 8)
  441.          printf("skipinterp till %s at %s\n", stoppers ? stoppers : "", pattern);
  442. #endif
  443.  
  444.       if (*pattern == '%' && pattern[1])
  445.       {
  446.          switch (*++pattern)
  447.          {
  448.           case '{':
  449.             for (pattern++; *pattern && *pattern != '}'; pattern++)
  450.                if (*pattern == '\\')
  451.                   pattern++;
  452.             break;
  453.           case '[':
  454.             for (pattern++; *pattern && *pattern != ']'; pattern++)
  455.                if (*pattern == '\\')
  456.                   pattern++;
  457.             break;
  458.  
  459. #ifdef CONDSUB
  460.           case '(':
  461.             {
  462.                pattern = skipinterp(pattern + 1, "!=");
  463.                if (!*pattern)
  464.                   goto getout;
  465.                for (pattern++; *pattern && *pattern != '?'; pattern++)
  466.                   if (*pattern == '\\')
  467.                      pattern++;
  468.                if (!*pattern)
  469.                   goto getout;
  470.                pattern = skipinterp(pattern + 1, ":)");
  471.                if (*pattern == ':')
  472.                   pattern = skipinterp(pattern + 1, ")");
  473.                break;
  474.             }
  475. #endif
  476.  
  477. #ifdef BACKTICK
  478.           case '`':
  479.             {
  480.                pattern = skipinterp(pattern + 1, "`");
  481.                break;
  482.             }
  483. #endif
  484.  
  485. #ifdef PROMPTTTY
  486.           case '"':
  487.             pattern = skipinterp(pattern + 1, "\"");
  488.             break;
  489. #endif
  490.  
  491.           default:
  492.             break;
  493.          }
  494.          pattern++;
  495.       }
  496.       else
  497.       {
  498.          if (*pattern == '^' && pattern[1])
  499.             pattern += 2;
  500.          else if (*pattern == '\\' && pattern[1])
  501.             pattern += 2;
  502.          else
  503.             pattern++;
  504.       }
  505.    }
  506. getout:
  507.    return pattern;           /* where we left off */
  508. }
  509.  
  510. #endif
  511.  
  512. /* interpret interpolations */
  513.  
  514. char *
  515.   dointerp(dest, destsize, pattern, stoppers)
  516.    register char *dest;
  517.    register int destsize;
  518.    register char *pattern;
  519.    char *stoppers;
  520. {
  521.    char *subj_buf = Nullch;
  522.    char *ngs_buf = Nullch;
  523.    char *refs_buf = Nullch;
  524.    char *artid_buf = Nullch;
  525.    char *reply_buf = Nullch;
  526.    char *from_buf = Nullch;
  527.    char *path_buf = Nullch;
  528.    char *follow_buf = Nullch;
  529.    char *dist_buf = Nullch;
  530.    char *line_buf = Nullch;
  531.    register char *s, *h;
  532.    register int i;
  533.    char scrbuf[512];
  534.    bool upper = FALSE;
  535.    bool lastcomp = FALSE;
  536.    int metabit = 0;
  537.  
  538.    while (*pattern && (!stoppers || !index(stoppers, *pattern)))
  539.    {
  540.  
  541. #ifdef DEBUGGING
  542.       if (debug & 8)
  543.          printf("dointerp till %s at %s\n", stoppers ? stoppers : "", pattern);
  544. #endif
  545.  
  546.       if (*pattern == '%' && pattern[1])
  547.       {
  548.          upper = FALSE;
  549.          lastcomp = FALSE;
  550.          for (s = Nullch; !s;)
  551.          {
  552.             switch (*++pattern)
  553.             {
  554.              case '^':
  555.                upper = TRUE;
  556.                break;
  557.              case '_':
  558.                lastcomp = TRUE;
  559.                break;
  560.              case '/':
  561.  
  562. #ifdef ARTSRCH
  563.                s = scrbuf;
  564.                if (!index("/?g", pattern[-2]))
  565.                   *s++ = '/';
  566.                strcpy(s, lastpat);
  567.                s += strlen(s);
  568.                if (pattern[-2] != 'g')
  569.                {
  570.                   if (index("/?", pattern[-2]))
  571.                      *s++ = pattern[-2];
  572.                   else
  573.                      *s++ = '/';
  574.                   if (art_howmuch == 1)
  575.                      *s++ = 'h';
  576.                   else if (art_howmuch == 2)
  577.                      *s++ = 'a';
  578.                   if (art_doread)
  579.                      *s++ = 'r';
  580.                }
  581.                *s = '\0';
  582.                s = scrbuf;
  583. #else
  584.                s = nullstr;
  585. #endif
  586.  
  587.                break;
  588.              case '{':
  589.                pattern = cpytill(scrbuf, pattern + 1, '}');
  590.                if (s = index(scrbuf, '-'))
  591.                   *s++ = '\0';
  592.                else
  593.                   s = nullstr;
  594.                s = getval(scrbuf, s);
  595.                break;
  596.              case '[':
  597.                pattern = cpytill(scrbuf, pattern + 1, ']');
  598.                i = set_line_type(scrbuf, scrbuf + strlen(scrbuf));
  599.                if (line_buf)
  600.                   free(line_buf);
  601.                s = line_buf = fetchlines(art, i);
  602.                break;
  603.  
  604. #ifdef CONDSUB
  605.              case '(':
  606.                {
  607.                   COMPEX *oldbra_compex = bra_compex;
  608.                   COMPEX cond_compex;
  609.                   char rch;
  610.                   bool matched;
  611.  
  612.                   init_compex(&cond_compex);
  613.                   pattern = dointerp(dest, destsize, pattern + 1, "!=");
  614.                   rch = *pattern;
  615.                   if (rch == '!')
  616.                      pattern++;
  617.                   if (*pattern != '=')
  618.                      goto getout;
  619.                   pattern = cpytill(scrbuf, pattern + 1, '?');
  620.                   if (!*pattern)
  621.                      goto getout;
  622.                   if (s = compile(&cond_compex, scrbuf, TRUE, TRUE))
  623.                   {
  624.                      printf("%s: %s\n", scrbuf, s) FLUSH;
  625.                      pattern += strlen(pattern);
  626.                      goto getout;
  627.                   }
  628.                   matched = (execute(&cond_compex, dest) != Nullch);
  629.                   if (cond_compex.nbra) /* were there brackets? */
  630.                      bra_compex = &cond_compex;
  631.                   if (matched == (rch == '='))
  632.                   {
  633.                      pattern = dointerp(dest, destsize, pattern + 1, ":)");
  634.                      if (*pattern == ':')
  635.                         pattern = skipinterp(pattern + 1, ")");
  636.                   }
  637.                   else
  638.                   {
  639.                      pattern = skipinterp(pattern + 1, ":)");
  640.                      if (*pattern == ':')
  641.                         pattern++;
  642.                      pattern = dointerp(dest, destsize, pattern, ")");
  643.                   }
  644.                   s = dest;
  645.                   bra_compex = oldbra_compex;
  646.                   free_compex(&cond_compex);
  647.                   break;
  648.                }
  649. #endif
  650.  
  651. #ifdef BACKTICK
  652.              case '`':
  653.                {
  654.                   FILE *pipefp, *popen();
  655.  
  656.                   pattern = dointerp(scrbuf, (sizeof scrbuf), pattern + 1, "`");
  657.                   pipefp = popen(scrbuf, "r");
  658.                   if (pipefp != Nullfp)
  659.                   {
  660.                      int len;
  661.  
  662.                      len = fread(scrbuf, sizeof (char), (sizeof scrbuf) -1,
  663.                                  pipefp);
  664.                      scrbuf[len] = '\0';
  665.                      pclose(pipefp);
  666.                   }
  667.                   else
  668.                   {
  669.                      printf("\nCan't run %s\n", scrbuf);
  670.                      *scrbuf = '\0';
  671.                   }
  672.                   for (s = scrbuf; *s; s++)
  673.                   {
  674.                      if (*s == '\n')
  675.                      {
  676.                         if (s[1])
  677.                            *s = ' ';
  678.                         else
  679.                            *s = '\0';
  680.                      }
  681.                   }
  682.                   s = scrbuf;
  683.                   break;
  684.                }
  685. #endif
  686.  
  687. #ifdef PROMPTTTY
  688.              case '"':
  689.                pattern = dointerp(scrbuf, (sizeof scrbuf), pattern + 1, "\"");
  690.                fputs(scrbuf, stdout) FLUSH;
  691.                resetty();
  692.                gets(scrbuf);
  693.                noecho();
  694.                crmode();
  695.                s = scrbuf;
  696.                break;
  697. #endif
  698.  
  699.              case '~':
  700.                s = homedir;
  701.                break;
  702.              case '.':
  703.                s = dotdir;
  704.                break;
  705.              case '$':
  706.                s = scrbuf;
  707.                sprintf(s, "%d", getpid());
  708.                break;
  709.              case '0':
  710.              case '1':
  711.              case '2':
  712.              case '3':
  713.              case '4':
  714.              case '5':
  715.              case '6':
  716.              case '7':
  717.              case '8':
  718.              case '9':
  719.  
  720. #ifdef CONDSUB
  721.                s = getbracket(bra_compex, *pattern - '0');
  722. #else
  723.                s = nullstr;
  724. #endif
  725.  
  726.                break;
  727.              case 'a':
  728.                s = scrbuf;
  729.                sprintf(s, "%ld", (long) art);
  730.                break;
  731.              case 'A':
  732.  
  733. #ifdef LINKART
  734.                s = linkartname; /* so Eunice people get right file */
  735. #else
  736.                s = scrbuf;
  737.                ImportNewsGroup( s, ngdir, art );
  738. #endif
  739.  
  740.                break;
  741.              case 'b':
  742.                s = savedest;
  743.                break;
  744.              case 'B':
  745.                s = scrbuf;
  746.                sprintf(s, "%ld", (long) savefrom);
  747.                break;
  748.              case 'c':
  749.                s = ngdir;
  750.                break;
  751.              case 'C':
  752.                s = ngname;
  753.                break;
  754.              case 'd':
  755.                s = scrbuf;
  756.                strcpy( s, ngdir );
  757.                break;
  758.              case 'D':
  759.                s = dist_buf = fetchlines(art, DIST_LINE);
  760.                break;
  761.              case 'f':       /* from line */
  762.  
  763. #ifdef ASYNC_PARSE
  764.                parse_maybe(art);
  765. #endif
  766.  
  767.                if (htype[REPLY_LINE].ht_minpos >= 0)
  768.                {
  769.                   /* was there a reply line? */
  770.                   if (!(s = reply_buf))
  771.                      s = reply_buf = fetchlines(art, REPLY_LINE);
  772.                }
  773.                else if (!(s = from_buf))
  774.                   s = from_buf = fetchlines(art, FROM_LINE);
  775.                break;
  776.              case 'F':
  777.  
  778. #ifdef ASYNC_PARSE
  779.                parse_maybe(art);
  780. #endif
  781.  
  782.                if (htype[FOLLOW_LINE].ht_minpos >= 0)
  783.                   /* is there a Followup-To line? */
  784.                   s = follow_buf = fetchlines(art, FOLLOW_LINE);
  785.                else
  786.                {
  787.                   int off;
  788.  
  789.                   s = ngs_buf = fetchlines(art, NGS_LINE);
  790.                   if (h = instr(s, "net.general"))
  791.                   {
  792.                      off = h - s;
  793.                      strncpy(scrbuf, s, off + 4);
  794.                      strcpy(scrbuf + off + 4, "followup");
  795.                      safecpy(scrbuf + off + 12, h + 11, sizeof (scrbuf));
  796.                      s = scrbuf;
  797.                   }
  798.                }
  799.                break;
  800.              case 'h':       /* header file name */
  801.                s = headname;
  802.                break;
  803.              case 'H':       /* host name */
  804.                s = sitename;
  805.                break;
  806.              case 'i':
  807.                if (!(s = artid_buf))
  808.                   s = artid_buf = fetchlines(art, MESSID_LINE);
  809.                if (*s && *s != '<')
  810.                {
  811.                   sprintf(scrbuf, "<%s>", artid_buf);
  812.                   s = scrbuf;
  813.                }
  814.                break;
  815.              case 'I':       /* ref article indicator */
  816.                s = scrbuf;
  817.                sprintf(scrbuf, "'%s'", indstr);
  818.                break;
  819.              case 'J':       /* tmp directory */
  820.                s = tmpdir;
  821.                break;
  822.              case 'l':       /* rn library */
  823.  
  824. #ifdef NEWSADMIN
  825.                s = newsadmin;
  826. #else
  827.                s = "???";
  828. #endif
  829.  
  830.                break;
  831.              case 'L':       /* login id */
  832.                s = logname;
  833.                break;
  834.              case 'm':       /* current mode */
  835.                s = scrbuf;
  836.                *s = mode;
  837.                s[1] = '\0';
  838.                break;
  839.              case 'M':
  840.  
  841. #ifdef DELAYMARK
  842.                sprintf(scrbuf, "%ld", (long) dmcount);
  843.                s = scrbuf;
  844. #else
  845.                s = nullstr;
  846. #endif
  847.  
  848.                break;
  849.              case 'n':       /* newsgroups */
  850.                s = ngs_buf = fetchlines(art, NGS_LINE);
  851.                break;
  852.              case 'N':       /* full name */
  853.                s = getval("NAME", realname);
  854.                break;
  855.              case 'o':       /* organization */
  856.                s = getval("ORGANIZATION", orgname);
  857.  
  858. #ifdef ORGFILE
  859.                if (*s == '/')
  860.                {
  861.                   FILE *ofp = fopen(s, "r");
  862.  
  863.                   if (ofp)
  864.                   {
  865.                      fgets(scrbuf, sizeof scrbuf, ofp);
  866.                      fclose(ofp);
  867.                      s = scrbuf;
  868.                      s[strlen(s) - 1] = '\0';
  869.                   }
  870.                }
  871. #endif
  872.  
  873.                break;
  874.              case 'O':
  875.                s = origdir;
  876.                break;
  877.              case 'p':
  878.                s = cwd;
  879.                break;
  880.              case 'P':
  881.                s = spool;
  882.                break;
  883.              case 'r':
  884.  
  885. #ifdef ASYNC_PARSE
  886.                parse_maybe(art);
  887. #endif
  888.  
  889.                if (htype[REFS_LINE].ht_minpos >= 0)
  890.                {
  891.                   refs_buf = fetchlines(art, REFS_LINE);
  892.                   refscpy(scrbuf, (sizeof scrbuf), refs_buf);
  893.                }
  894.                else
  895.                   *scrbuf = '\0';
  896.                s = rindex(scrbuf, '<');
  897.                break;
  898.              case 'R':
  899.  
  900. #ifdef ASYNC_PARSE
  901.                parse_maybe(art);
  902. #endif
  903.  
  904.                if (htype[REFS_LINE].ht_minpos >= 0)
  905.                {
  906.                   refs_buf = fetchlines(art, REFS_LINE);
  907.                   refscpy(scrbuf, (sizeof scrbuf), refs_buf);
  908.                   /* no more than 3 prior references allowed, * including the
  909.                    * one concatenated below */
  910.                   if ((s = rindex(scrbuf, '<')) > scrbuf)
  911.                   {
  912.                      *s = '\0';
  913.                      h = rindex(scrbuf, '<');
  914.                      *s = '<';
  915.                      if (h > scrbuf)
  916.                         strcpy(scrbuf, h);
  917.                   }
  918.                }
  919.                else
  920.                   *scrbuf = '\0';
  921.                if (!artid_buf)
  922.                   artid_buf = fetchlines(art, MESSID_LINE);
  923.                if (artid_buf[0] == '<')
  924.                   safecat(scrbuf, artid_buf, sizeof (scrbuf));
  925.                else if (artid_buf[0])
  926.                {
  927.                   char tmpbuf[64];
  928.  
  929.                   sprintf(tmpbuf, "<%s>", artid_buf);
  930.                   safecat(scrbuf, tmpbuf, sizeof (scrbuf));
  931.                }
  932.                s = scrbuf;
  933.                break;
  934.              case 's':
  935.                if (!(s = subj_buf))
  936.                   s = subj_buf = fetchsubj(art, TRUE, TRUE);
  937.                /* get subject handy */
  938.                while ((*s == 'R' || *s == 'r') && (s[1] == 'E' || s[1] == 'e') && s[2] == ':')
  939.                {
  940.                   /* skip extra Re: */
  941.                   s += 3;
  942.                   if (*s == ' ')
  943.                      s++;
  944.                }
  945.                if (h = instr(s, "- (nf"))
  946.                   *h = '\0';
  947.                break;
  948.              case 'S':
  949.                if (!(s = subj_buf))
  950.                   s = subj_buf = fetchsubj(art, TRUE, TRUE);
  951.                /* get subject handy */
  952.                if ((*s == 'R' || *s == 'r') && (s[1] == 'E' || s[1] == 'e') && s[2] == ':')
  953.                {
  954.                   /* skip extra Re: */
  955.                   s += 3;
  956.                   if (*s == ' ')
  957.                      s++;
  958.                }
  959.                break;
  960.              case 't':
  961.              case 'T':
  962.  
  963. #ifdef ASYNC_PARSE
  964.                parse_maybe(art);
  965. #endif
  966.  
  967.                if (htype[REPLY_LINE].ht_minpos >= 0)
  968.                {
  969.                   /* was there a reply line? */
  970.                   if (!(s = reply_buf))
  971.                      s = reply_buf = fetchlines(art, REPLY_LINE);
  972.                }
  973.                else if (!(s = from_buf))
  974.                   s = from_buf = fetchlines(art, FROM_LINE);
  975.                if (*pattern == 'T')
  976.                {
  977.                   if (htype[PATH_LINE].ht_minpos >= 0)
  978.                   {
  979.                      /* should we substitute path? */
  980.                      s = path_buf = fetchlines(art, PATH_LINE);
  981.                   }
  982.                   i = strlen(sitename);
  983.                   if (strnEQ(sitename, s, i) && s[i] == '!')
  984.                      s += i + 1;
  985.                }
  986.                if ((h = index(s, '(')) != Nullch)
  987.                   /* strip garbage from end */
  988.                   *(h - 1) = '\0';
  989.                else if ((h = index(s, '<')) != Nullch)
  990.                {
  991.                   /* or perhaps from beginning */
  992.                   s = h + 1;
  993.                   if ((h = index(s, '>')) != Nullch)
  994.                      *h = '\0';
  995.                }
  996.                break;
  997.              case 'u':
  998.                sprintf(scrbuf, "%ld", (long) toread[ng]);
  999.                s = scrbuf;
  1000.                break;
  1001.              case 'U':
  1002.                sprintf(scrbuf, "%ld",
  1003.                        (long) (((ART_NUM) toread[ng]) - 1 + was_read(art)));
  1004.                s = scrbuf;
  1005.                break;
  1006.              case 'x':       /* news library */
  1007.                s = lib;
  1008.                break;
  1009.              case 'X':       /* rn library */
  1010.                s = rnlib;
  1011.                break;
  1012.              case 'z':
  1013.  
  1014. #ifdef LINKART
  1015.                s = linkartname; /* so Eunice people get
  1016.                                  * right file */
  1017. #else
  1018.                s = scrbuf;
  1019.                sprintf(s, "%ld", (long) art);
  1020. #endif
  1021.  
  1022.                if (stat(s, &filestat) < 0)
  1023.                   filestat.st_size = 0L;
  1024.                sprintf(scrbuf, "%5ld", (long) filestat.st_size);
  1025.                s = scrbuf;
  1026.                break;
  1027.              default:
  1028.                if (--destsize <= 0)
  1029.                   abort_interp();
  1030.                *dest++ = *pattern | metabit;
  1031.                s = nullstr;
  1032.                break;
  1033.             }
  1034.          }
  1035.          if (!s)
  1036.             s = nullstr;
  1037.          pattern++;
  1038.          if (upper || lastcomp)
  1039.          {
  1040.             char *t;
  1041.  
  1042.             if (s != scrbuf)
  1043.             {
  1044.                safecpy(scrbuf, s, (sizeof scrbuf));
  1045.                s = scrbuf;
  1046.             }
  1047.             if (upper || !(t = rindex(s, '/')))
  1048.                t = s;
  1049.             while (*t && !isalpha(*t))
  1050.                t++;
  1051.             if (islower(*t))
  1052.                *t = toupper(*t);
  1053.          }
  1054.          i = metabit;        /* maybe get into
  1055.                               * register */
  1056.          if (s == dest)
  1057.          {
  1058.             while (*dest)
  1059.             {
  1060.                if (--destsize <= 0)
  1061.                   abort_interp();
  1062.                *dest++ |= i;
  1063.             }
  1064.          }
  1065.          else
  1066.          {
  1067.             while (*s)
  1068.             {
  1069.                if (--destsize <= 0)
  1070.                   abort_interp();
  1071.                *dest++ = *s++ | i;
  1072.             }
  1073.          }
  1074.       }
  1075.       else
  1076.       {
  1077.          if (--destsize <= 0)
  1078.             abort_interp();
  1079.          if (*pattern == '^' && pattern[1])
  1080.          {
  1081.             ++pattern;       /* skip uparrow */
  1082.             i = *pattern;    /* get char into a
  1083.                               * register */
  1084.             if (i == '?')
  1085.                *dest++ = '\177' | metabit;
  1086.             else if (i == '(')
  1087.             {
  1088.                metabit = 0200;
  1089.                destsize++;
  1090.             }
  1091.             else if (i == ')')
  1092.             {
  1093.                metabit = 0;
  1094.                destsize++;
  1095.             }
  1096.             else
  1097.                *dest++ = i & 037 | metabit;
  1098.             pattern++;
  1099.          }
  1100.          else if (*pattern == '\\' && pattern[1])
  1101.          {
  1102.             ++pattern;       /* skip backslash */
  1103.             i = *pattern;    /* get char into a
  1104.                               * register */
  1105.  
  1106.             /* this used to be a switch but the if may save space */
  1107.  
  1108.             if (i >= '0' && i <= '7')
  1109.             {
  1110.                i = 1;
  1111.                while (i < 01000 && *pattern >= '0' && *pattern <= '7')
  1112.                {
  1113.                   i <<= 3;
  1114.                   i += *pattern++ - '0';
  1115.                }
  1116.                *dest++ = i & 0377 | metabit;
  1117.                --pattern;
  1118.             }
  1119.             else if (i == 'b')
  1120.                *dest++ = '\b' | metabit;
  1121.             else if (i == 'f')
  1122.                *dest++ = '\f' | metabit;
  1123.             else if (i == 'n')
  1124.                *dest++ = '\n' | metabit;
  1125.             else if (i == 'r')
  1126.                *dest++ = '\r' | metabit;
  1127.             else if (i == 't')
  1128.                *dest++ = '\t' | metabit;
  1129.             else
  1130.                *dest++ = i | metabit;
  1131.             pattern++;
  1132.          }
  1133.          else
  1134.             *dest++ = *pattern++ | metabit;
  1135.       }
  1136.    }
  1137.    *dest = '\0';
  1138. getout:
  1139.    if (subj_buf != Nullch)   /* return any checked
  1140.                               * out storage */
  1141.       free(subj_buf);
  1142.    if (ngs_buf != Nullch)
  1143.       free(ngs_buf);
  1144.    if (refs_buf != Nullch)
  1145.       free(refs_buf);
  1146.    if (artid_buf != Nullch)
  1147.       free(artid_buf);
  1148.    if (reply_buf != Nullch)
  1149.       free(reply_buf);
  1150.    if (from_buf != Nullch)
  1151.       free(from_buf);
  1152.    if (path_buf != Nullch)
  1153.       free(path_buf);
  1154.    if (follow_buf != Nullch)
  1155.       free(follow_buf);
  1156.    if (dist_buf != Nullch)
  1157.       free(dist_buf);
  1158.    if (line_buf != Nullch)
  1159.       free(line_buf);
  1160.    return pattern;           /* where we left off */
  1161. }
  1162.  
  1163. void
  1164.   interp(dest, destsize, pattern)
  1165.    char *dest;
  1166.    int destsize;
  1167.    char *pattern;
  1168. {
  1169.    dointerp(dest, destsize, pattern, Nullch);
  1170.  
  1171. #ifdef DEBUGGING
  1172.    if (debug & DEB_FILEXP)
  1173.       fputs(dest, stdout);
  1174. #endif
  1175. }
  1176.  
  1177. /* copy a references line, normalizing as we go */
  1178.  
  1179. void
  1180.   refscpy(dest, destsize, src)
  1181.    register char *dest, *src;
  1182.    register int destsize;
  1183. {
  1184.    register char *dot, *at, *beg;
  1185.    char tmpbuf[64];
  1186.  
  1187.    while (*src)
  1188.    {
  1189.       if (*src != '<')
  1190.       {
  1191.          if (--destsize <= 0)
  1192.             break;
  1193.          *dest++ = '<';
  1194.          at = dot = Nullch;
  1195.          beg = src;
  1196.          while (*src && *src != ' ' && *src != ',')
  1197.          {
  1198.             if (*src == '.')
  1199.                dot = src;
  1200.             else if (*src == '@')
  1201.                at = src;
  1202.             if (--destsize <= 0)
  1203.                break;
  1204.             *dest++ = *src++;
  1205.          }
  1206.          if (destsize <= 0)
  1207.             break;
  1208.          if (dot && !at)
  1209.          {
  1210.             int len;
  1211.  
  1212.             *dest = *dot++ = '\0';
  1213.             sprintf(tmpbuf, "%s@%s.UUCP", dot, beg);
  1214.             len = strlen(tmpbuf);
  1215.             if (destsize > len)
  1216.             {
  1217.                strcpy(dest, tmpbuf);
  1218.                dest = dest + len;
  1219.                destsize -= len;
  1220.             }
  1221.          }
  1222.          if (--destsize <= 0)
  1223.             break;
  1224.          *dest++ = '>';
  1225.       }
  1226.       else
  1227.       {
  1228.          while (*src && --destsize > 0 && (*dest++ = *src++) != '>');
  1229.          if (destsize <= 0)
  1230.             break;
  1231.       }
  1232.       while (*src == ' ' || *src == ',')
  1233.          src++;
  1234.       if (*src && --destsize > 0)
  1235.          *dest++ = ' ';
  1236.    }
  1237.    *dest = '\0';
  1238. }
  1239.  
  1240. /* get the person's real name from /etc/passwd */
  1241. /* (string is overwritten, so it must be copied) */
  1242.  
  1243. char *
  1244.   getrealname(uid)
  1245.    int uid;
  1246. {
  1247.    char *s, *c;
  1248.  
  1249. #ifdef PASSNAMES
  1250.  
  1251. #ifdef GETPWENT
  1252.    struct passwd *pwd = getpwuid(uid);
  1253.  
  1254.    s = pwd->pw_gecos;
  1255. #else
  1256.    char tmpbuf[512];
  1257.    int i;
  1258.  
  1259.    getpw(uid, tmpbuf);
  1260.    for (s = tmpbuf, i = GCOSFIELD - 1; i; i--)
  1261.    {
  1262.       if (s)
  1263.          s = index(s, ':') + 1;
  1264.    }
  1265.    if (!s)
  1266.       return nullstr;
  1267.    cpytill(tmpbuf, s, ':');
  1268.    s = tmpbuf;
  1269. #endif
  1270.  
  1271. #ifdef BERKNAMES
  1272.  
  1273. #ifdef BERKJUNK
  1274.    while (*s && !isalnum(*s) && *s != '&')
  1275.       s++;
  1276. #endif
  1277.  
  1278.    if ((c = index(s, ',')) != Nullch)
  1279.       *c = '\0';
  1280.    if ((c = index(s, ';')) != Nullch)
  1281.       *c = '\0';
  1282.    s = cpytill(buf, s, '&');
  1283.    if (*s == '&')
  1284.    {                         /* whoever thought this
  1285.                               * one up was */
  1286.       c = buf + strlen(buf); /* in the middle of the
  1287.                               * night */
  1288.       strcat(c, logname);    /* before the morning
  1289.                               * after */
  1290.       strcat(c, s + 1);
  1291.       if (islower(*c))
  1292.          *c = toupper(*c);   /* gack and double gack */
  1293.    }
  1294. #else
  1295.    if ((c = index(s, '(')) != Nullch)
  1296.       *c = '\0';
  1297.    if ((c = index(s, '-')) != Nullch)
  1298.       s = c;
  1299.    strcpy(buf, tmpbuf);
  1300. #endif
  1301.  
  1302. #ifdef GETPWENT
  1303.    endpwent();
  1304. #endif
  1305.  
  1306.    return buf;               /* return something
  1307.                               * static */
  1308. #else
  1309.  
  1310. #ifdef msdos
  1311.    if (E_name)
  1312.       return E_name;
  1313. #endif                       /* msdos */
  1314.  
  1315.    if ((tmpfp = fopen(filexp(FULLNAMEFILE), "r")) != Nullfp)
  1316.    {
  1317.       fgets(buf, sizeof buf, tmpfp);
  1318.       fclose(tmpfp);
  1319.       buf[strlen(buf) - 1] = '\0';
  1320.       return buf;
  1321.    }
  1322.    return "PUT YOUR NAME HERE";
  1323. #endif
  1324. }
  1325.  
  1326. static void
  1327.   abort_interp()
  1328. {
  1329.    fputs("\n% interp buffer overflow!\n", stdout) FLUSH;
  1330.    sig_catcher(0);
  1331. }
  1332.